package com.learn.temp.api;

import com.learn.temp.api.annotation.MyAutoWried;

import javax.swing.plaf.metal.MetalTheme;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.stream.Stream;

/**
 * @author wangxing
 * @version 2020/8/5 9:31 Administrator
 */
public class ReflectDemo {
  public class AController{
        @MyAutoWried
        private BService bService;

        public BService getBService() {
            return bService;
        }

        public void setBService(BService bService) {
            this.bService = bService;
        }
    }
   public class BService{
        public void print(){
            System.out.println("i am b");
        }
    }

    public static void main(String[] args) {
        ReflectDemo r = new ReflectDemo();
        r.reflectSetFieldAnnotation();
        try {
            r.reflectSetFieldOriginal();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 反射注入属性 --- 原生
     * @throws NoSuchFieldException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public void reflectSetFieldOriginal() throws NoSuchFieldException, NoSuchMethodException, InvocationTargetException,
            IllegalAccessException {
        AController a = new AController();
        Class<? extends AController> clazz = a.getClass();
        BService b = new BService();
//        获取所有的属性
        Field field = clazz.getDeclaredField("bService");
        field.setAccessible(true);
//        获取属性名
        String name = field.getName();
        name = name.substring(0,1).toUpperCase() + name.substring(1,name.length());
//        拼接方法名
        String setMethodName = "set"+name;
//        通过方法名注入属性的对象
        Method method = clazz.getMethod(setMethodName, b.getClass());
//        反射注入
        method.invoke(a,b);
        a.getBService().print();
    }

    /**
     * 反射注入属性 --- 通过自定义注解的方式实现
     */
    public void reflectSetFieldAnnotation(){
        AController a = new AController();
        Class<? extends AController> clazz = a.getClass();
        Stream.of(clazz.getDeclaredFields()).forEach((field)->{
            MyAutoWried autoWried = field.getAnnotation(MyAutoWried.class);
            if(autoWried!=null){
                field.setAccessible(true);
                Class<?> type = field.getType();
                try {
                    Object o = type.newInstance();
                    field.set(a, o);
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        });
        a.getBService().print();
    }
}
